feat: local Keycloak mock + backend auth env wiring#198
Open
vredchenko wants to merge 3 commits into
Open
Conversation
The smartem-frontend Keycloak integration currently has no local
development story — every dev needs `http://localhost:5173` added to
the SmartEM client's Valid Redirect URIs and Web Origins on
`identity-test.diamond.ac.uk`, which is an admin round-trip that has
to be repeated for every new port and every new developer.
A self-contained mock removes that dependency:
- `dls-realm.json` is the single source of truth — realm `dls`,
public client `SmartEM` with PKCE, localhost redirect URIs and
Web Origins, custom `fedId` claim mapper, two seeded users.
- Compose form for the fastest standalone cycle.
- Kustomize form integrated into the existing development overlay,
so `dev-k8s.sh up` now brings up Keycloak alongside the rest of
the stack.
Both forms read the same realm JSON, so editing it once propagates
to whichever form a developer prefers.
The architecture doc gains a "Local development" pointer and the
client-name discrepancy (`smartem-frontend` vs `SmartEM`) is
corrected to match the actual implementation.
…p-api The development environment's `smartem-http-api-service` already claims NodePort 30080. Applying the keycloak-mock kustomization to the development overlay therefore fails with a port conflict. Move the keycloak-external Service to 30090 and update the three doc references that mention 30080. The browser-facing URL becomes `http://<node-ip>:30090`; the ClusterIP path (`http://keycloak-service:8080`) is unchanged.
The backend (smartem-decisions) now consumes KEYCLOAK_AUTH_REQUIRED /
KEYCLOAK_URL / KEYCLOAK_REALM / KEYCLOAK_CLIENT_ID / KEYCLOAK_VERIFY_ISS to
gate Bearer-token validation against a Keycloak realm's JWKS.
- Staging defaults to the real DLS test realm
(https://identity-test.diamond.ac.uk, realm `dls`, client `SmartEM`)
with auth required and iss verification on.
- Development defaults to the in-cluster keycloak-mock service
(http://keycloak-service:8080) with iss verification OFF. Tokens are
minted with the browser-facing URL (localhost:30090) while the pod
reaches Keycloak via in-cluster DNS, so issuer strings don't match
even though the signing key does. Auth itself defaults to disabled
in dev so existing workflows that don't pass a token still work;
flip it on per developer via `.env.k8s.development`.
`dev-k8s.sh ensure_app_configmap()` now also reads the five Keycloak
variables from the environment and bakes them into the dynamically-
generated ConfigMap, so an operator who edits `.env.k8s.staging` and runs
`DEPLOY_ENV=staging ./scripts/k8s/dev-k8s.sh up` gets the right values
without touching YAML.
Examples in `env-examples/.env.example.k8s.{staging,development}` are
updated to document the new variables.
7 tasks
6 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
Two things had to land together:
http://localhost:5173isn't in theSmartEMclient's redirect URIs onidentity-test.diamond.ac.uk, and getting it added is an admin round-trip per port and per developer.dev-k8s.shneed to carry the sameKEYCLOAK_*settings so the pod can fetch JWKS in-cluster.This PR covers both: a self-contained Keycloak mock for the frontend, and the env-wiring that lets the backend point at it (or at the real DLS realm in staging) without YAML surgery.
What's included
Self-contained Keycloak mock (
keycloak-mock/)Two equivalent deployment forms, both reading from one realm export:
dls-realm.json— single source of truth. Realmdls, public clientSmartEMwith PKCE S256,localhost:5173andlocalhost:5174in redirect URIs and Web Origins, customfedIdclaim mapper to mirror DLS realm claims, two seeded users (devuser/devpass,valuser/valpass).docker-compose.yml— Compose form, fastest standalone cycle (~20 s).keycloak.yaml+kustomization.yaml— Kubernetes Deployment + Services + kustomizeconfigMapGeneratorfor the realm JSON.The Kustomize form is wired into
k8s/environments/development/kustomization.yaml, so./scripts/k8s/dev-k8s.sh upbrings up Keycloak alongside Postgres, RabbitMQ, etc. The Compose form is independent and useful when only the frontend is needed.Backend Keycloak env wiring
smartem-configConfigMap (bothdevelopmentandstagingoverlays) gains:KEYCLOAK_AUTH_REQUIRED— master switch consumed by the backend (defaults:falsein dev,truein staging)KEYCLOAK_URL— dev points athttp://keycloak-service:8080(in-cluster DNS); staging points athttps://identity-test.diamond.ac.ukKEYCLOAK_REALM,KEYCLOAK_CLIENT_ID,KEYCLOAK_VERIFY_ISSDev has
KEYCLOAK_VERIFY_ISS=falsebecause tokens are minted with the browser-facing URL (localhost:30090) while the pod reaches Keycloak via in-cluster DNS — signing key is identical butissstrings differ. Staging hasissverification on.dev-k8s.sh ensure_app_configmap()reads the five vars from the environment and bakes them into the dynamically-generated ConfigMap. Operators only need to edit.env.k8s.<env>— corresponding examples inenv-examples/are updated.Port-conflict fix (
fix(keycloak-mock): move NodePort to 30090)The development environment's
smartem-http-api-servicealready claimed NodePort30080. Applying the dev kustomization with the keycloak mock therefore failed with a port conflict. Movedkeycloak-externalto30090and updated the three doc references.Docs
docs/development/local-keycloak.md— full how-to (when to use which form, how to point the frontend at it, how to edit the realm, limits and non-goals).docs/development/index.md— added to the TOC.docs/architecture/keycloak-spa-authentication.md— "Local development" pointer + corrected thesmartem-frontend→SmartEMclient-name discrepancy.Quick start
Then in
smartem-frontend/apps/smartem/.env.local:Log in as
devuser/devpass.Verified end-to-end
The full chain — SPA -> Keycloak -> SPA with token -> backend
/acquisitions-> backend validates JWT againstkeycloak-service:8080JWKS -> 200 + payload — runs cleanly on a local single-node k3s with all three branches applied (#74, this PR, smartem-decisionsfeat/keycloak-jwt-validation).Test plan
kubectl kustomize keycloak-mockbuilds cleanlykubectl kustomize k8s/environments/developmentbuilds cleanly with Keycloak and KEYCLOAK_* envs includeddocker compose up -dinkeycloak-mock/imports thedlsrealm and exposes the admin console athttp://localhost:8080./scripts/k8s/dev-k8s.sh upbrings Keycloak up alongside the rest of the stack, reachable athttp://<node-ip>:30090KEYCLOAK_AUTH_REQUIRED=truefetches JWKS fromhttp://keycloak-service:8080and accepts a realdevusertoken